Java 2 Enterprise Edition™ (“J2EE”) is a specification for building and deploying distributed enterprise applications. Unlike traditional client-server systems, J2EE is based on a multi-tiered architecture in which server side program code is divided into several layers including a “presentation” layer and a “business logic” layer. This separation allows developers to keep the code responsible for presenting the user interface aspects of the application separate from the code running the “backend” or business logic of the application.
A separate J2EE container manages each of the different layers in a J2EE application. Containers are runtime environments that provide standard common services to runtime components. For instance, the J2EE application server may contain presentation code implemented as Java Server Pages™ (“JSP”) or Java Servlets™. These components run within the J2EE web container, which is responsible for managing Hypertext Transfer Protocol (“HTTP”) or secure HTTP (“HTTPS”) connections. The J2EE application server may also contain business-logic implemented as Enterprise Java Beans™ (“EJB”). These components run within the J2EE EJB container, which is responsible for creating, destroying, and otherwise managing the EJB object instances.
Clients may access an application running on a J2EE server in a variety of different ways. For example, a client may use a web-browser to access the application through its web container. Alternatively, a client may use a stand-alone client application to access the business-logic in the EJB container via Remote Method Invocation (“RMI”), Common Object Request Broker Architecture (“CORBA”), or the like.
Regardless of how the client accesses the system, the server-side application is generally responsible for managing the session data associated with each client interaction. Session data defines the current conversational state between a client and the application server. For example, if the user is purchasing books from an online bookstore, the session data may define the current state of the user's “shopping cart” (e.g., the books the user has selected for purchase). Similarly, an application may require the user to login and session data is often used to hold the login authentication information for the duration of the client's transaction.
Session data is only needed while the client is using the application and may be discarded after the user is finished. As such, session data is not typically stored in a database, which would add unnecessary overhead to the application. Instead session data is stored in memory where it may be accessed quickly. The J2EE environment provides stateful session beans for this purpose. Stateful session beans are business logic objects that are associated with a specific client session and, as such, may be used to hold client-specific session data. The EJB container is responsible for managing stateful session beans and associating them with the proper client session.
Stateful Session Beans allow J2EE applications to deliver complex applications efficiently by keeping track of client-specific session data, but their use can lead to server resource problems. Each stateful session bean instance requires system resources and the EJB container can only support a finite number at any given time. This problem is exacerbated because it is often difficult for the EJB container to determine when stateful session bean objects can be safely removed. For instance, when a client is finished using a web-based application she may simply close the web-browser instead of first logging out; thus, since HTTP is a connectionless protocol, the EJB container will not receive any indication that the user is finished using the application. As such, the EJB container will not know that it is safe to remove the stateful session beans associated with that client since, as far as the EJB container is concerned, the client is still using the application. If enough users exit the system in this manner there will eventually be enough “dead-letter” stateful session bean instances to completely consume the server's resources.
Traditionally, EJB containers have addressed this problem using a Least Recently Used (“LRU”) style approach to remove old stateful session beans. In this method, the EJB container keeps a record of the time each bean was last accessed by a client. Then, in the event that application server memory resources become scarce, those beans with the longest time since last access (least recently used) are removed from memory and stored on disk. Finally, if beans are not requested from disk for some period of time, they are completely erased. This approach has a number of limitations. First, the timeout management code is completely encapsulated within the EJB container. As such, if an application uses more than one EJB container, the EJB timeout management service is unnecessarily duplicated. Second, EJBs may allocate system resources that should be released when the bean is removed. According to the EJB specification, code to release these resources is placed in the bean's ejbRemove( ) method to be invoked as the EJB container removes the bean. However, since timed-out EJBs are stored on disk before being erased, their ejbRemove( ) method is never invoked, creating the potential for resource leaks. Third, disk access to store and remove timed-out EJBs is relatively slow and can degrade server performance. Finally, each time a bean is accessed the EJB container must make a time-consuming call to the system clock to set the bean's last access time, further degrading server performance.